package com.xiaozhu.controller;


import com.xiaozhu.anno.AiLogExecute;
import com.xiaozhu.anno.ChatType;
import com.xiaozhu.common.aiconstant.ExecuteConstants;
import com.xiaozhu.pojo.dto.ChatDto;
import com.xiaozhu.repository.Impl.InMemoryChatHistoryRepository;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

/**
 * @author 朱慧军
 * @version 1.0
 */
@RestController
@RequestMapping("/ai")
@Slf4j
@AiLogExecute({ExecuteConstants.EXECUTE})
public class ChatController {


    @Autowired
    private ChatClient chatClient;

    @Autowired
    private InMemoryChatHistoryRepository inMemoryChatHistoryRepository;

    /**
     * 聊天接口
     *
     * URL: GET /ai/chat?prompt=你好
     * @return Flux<String> 以流的形式返回 AI 模型的响应内容，可实现实时逐条输出
     *
     * 使用说明：
     * 1. chatClient.prompt() 创建一个聊天请求
     * 2. .user(prompt) 设置用户输入提示词
     * 3. .stream() 表示以流式模式调用 AI 模型
     * 4. .content() 获取返回内容的字符串 Flux 流
     *
     * 适合前端做实时响应，例如 WebSocket 或 SSE 推送。@
     */
    @ChatType({"model::deepSeek}"})
    @PostMapping("/chat/flux")
    // 🔧 输入验证：添加 @Valid 注解，自动验证 ChatDto 的所有字段
    // 如果验证失败，会自动抛出 MethodArgumentNotValidException，由全局异常处理器处理
    public Flux<String> chat(ChatDto chatDto) {
        log.info("接收到的chatDto：{}", chatDto);
        
        // 🔧 删除：手动验证已被 Bean Validation 替代
        // 现在由 @Valid 注解自动验证，验证规则在 ChatDto 中定义
        // if (chatDto.getChatId() == null) {
        //     log.error("chatId 为空，无法保存对话历史");
        //     return Flux.error(new IllegalArgumentException("chatId 不能为空"));
        // }

        return Mono.fromCallable(() -> {
            inMemoryChatHistoryRepository.save(chatDto);
            return null;})
                .subscribeOn(Schedulers.boundedElastic())
                .thenMany(chatClient.prompt()
                        .user(chatDto.getPrompt())
                        //MessageChatMemoryAdvisor 会根据这个会话 ID 来 归类和保存消息。
                        //这样 AI 的每条对话消息（用户输入 + AI 输出）就不会混到其他会话里
                        .advisors(a -> {
                            // 转为 String 类型，确保与查询时一致
                            String chatIdStr = chatDto.getChatId().toString();
                            log.info("保存消息到 ChatMemory，chatId: {}", chatIdStr);
                            a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatIdStr);
                        })
                        .stream()
                        .content())
                .windowUntil(s -> s.contains("</think>"), true)  // 按 </think> 分段
                .flatMap(window -> window.reduce("", (acc, s) -> acc + s))  // 合并每段
                .filter(content -> !content.trim().isEmpty())  // 过滤空内容
                .map(this::filterThinkTags);  // 过滤 think 标签
    }
    
    /**
     * 过滤掉 <think>...</think> 标签及其内容
     * @param content 原始内容
     * @return 过滤后的内容
     */
    private String filterThinkTags(String content) {
        // 移除 <think>...</think> 及其内容
        String filtered = content.replaceAll("<think>.*?</think>", "");
        // 移除可能残留的单独标签
        filtered = filtered.replaceAll("</?think>", "");

        return filtered.trim();
    }

}

